<script>
    import {
        findMeterTypeOptions,
        findMeterByMeterType,
        findPropertMeterType,
    } from '@/api/common.js'
    import _ from 'lodash'
    import { findPropertyCalExpression, updatePropertyCalExpression } from '@/api/measurDevice'

    export default {
        name: 'FormModal',
        props: {
            title: String,
            rowData: Object,
        },
        data() {
            const rowData = this.$props.rowData
            return {
                loading: false,
                formData: {
                    id: rowData?.id || '',
                    meterType: rowData.typeId,
                    tableData: [],
                },
                meterTypeOptions: [], // 类型
                meterUtensilOptions: [], //  实体计量器具名称
                propertiesOptions: [], // 测点名称
            }
        },
        created() {
            this.initSetModal()
        },
        mounted() {
            this.initData()
        },
        methods: {
            getUUID() {
                return Math.random().toString(36).substr(3)
            },
            async initData() {
                try {
                    this.loading = true
                    const typeResult = await findMeterTypeOptions()
                    this.meterTypeOptions = typeResult.data || []

                    // getList
                    const listResult = await findPropertyCalExpression(this.formData.id)

                    const { meterType } = this.formData
                    // 计量器具
                    findMeterByMeterType(this.$store.state.projectId, meterType)
                        .then((resp) => {
                            this.meterUtensilOptions = resp.data
                        })
                        .finally(() => {
                            this.formData.tableData = this.normalizeTableData(listResult.data)
                            this.refreshRlTable()
                            this.loading = false
                        })

                    // 测点名称
                    findPropertMeterType(meterType).then((resp) => {
                        this.propertiesOptions = resp.data
                    })
                } catch (error) {
                    this.loading = false
                }
            },
            normalizeTableData(data) {
                return data.map((item) => {
                    if (!item.id) {
                        item.id = this.getUUID()
                    }
                    if (!item.factors || (item.factors && item.factors.length === 0)) {
                        item.factors = [{ meterUtensilId: '', properties: '' }]
                    }

                    if (!item.calculationRule) {
                        item.calculationRule = ''
                    }
                    item.factors = item.factors.map((factor) => {
                        factor.properties = factor.properties.split(',').filter((item) => item)
                        return factor
                    })
                    item.meterUtensilOptions = this.meterUtensilOptions
                    return item
                })
            },
            isSnowflakeId(data) {
                if (!data) {
                    return false
                }
                return data.startsWith('#') && data.endsWith('$')
            },
            parse(expression) {
                if (!expression) {
                    return []
                }
                // const regex = /#([^$]+)\$|\d+\.\d+|\d+%|[+\-*/()]/gu
                const regex = /#(?:[^$]+\$)|\d+\.\d+|\d+%?|[+\-*/()]/gu
                const matches = [...expression.matchAll(regex)].map((match) => match[0])
                // console.log(matches.flat(), "&&&&&&&&&&&&&&&&&&&&&");
                return matches.flat()
            },

            getMeterNameById(id, source) {
                const currentTarget = source.find((item) => item.value === id)
                return currentTarget ? currentTarget.key : ''
            },
            getPropertiesNameByCode(property, source) {
                const currentTarget = source.find((item) => item.property === property)
                return currentTarget ? currentTarget.name : ''
            },

            getMeterCodeById(key, source) {
                const currentTarget = source.find((item) => item.key === key)
                return currentTarget ? currentTarget.value : ''
            },
            getPropertiesCodeByCode(name, source) {
                const currentTarget = source.find((item) => item.name === name)
                return currentTarget ? currentTarget.property : ''
            },

            getMeterAndPropertiesText(item) {
                const textStr = item.slice(1, item.length - 1)
                const textArray = textStr.split('_')
                const meter = textArray.pop()
                const properties = textArray.join('_')
                return { meter, properties }
            },
            generateTextToken(textContext, meterUtensilOptions, propertiesOptions) {
                const { meter, properties } = this.getMeterAndPropertiesText(textContext)
                const currentMeterName = this.getMeterNameById(meter, meterUtensilOptions)
                const propertiesName = this.getPropertiesNameByCode(properties, propertiesOptions)
                return `#${propertiesName}_${currentMeterName}$`
            },
            generateCodeToken(item, meterUtensilOptions, propertiesOptions) {
                const { meter, properties } = this.getMeterAndPropertiesText(item)
                const currentMeterName = this.getMeterCodeById(meter, meterUtensilOptions)
                const propertiesName = this.getPropertiesCodeByCode(properties, propertiesOptions)
                return `#${propertiesName}_${currentMeterName}$`
            },

            transformToken(text, scope, type = 'zh') {
                if (!text || text.length === 0) {
                    return []
                }

                const fn = type === 'zh' ? this.generateTextToken : this.generateCodeToken
                const { meterUtensilOptions } = scope.row
                const propertiesOptions = this.propertiesOptions
                const tokens = this.parse(text)
                return tokens.map((item) => {
                    if (this.isSnowflakeId(item)) {
                        item = fn(item, meterUtensilOptions, propertiesOptions)
                    }
                    return item
                })
            },

            refreshRlTable(data) {
                this.$nextTick(() => {
                    const rlTable = this.$refs.rlTable
                    if (rlTable) {
                        rlTable.tableData = data || this.formData.tableData
                    }
                })
            },

            initSetModal() {
                this.$emit('SetTitle', this.$props.title)
                this.$emit('SetPageWidth', 1200)
                this.$emit('SetPageActions', [
                    {
                        text: '保存',
                        theme: 'primary',
                        handle: () => {
                            this.submitForm()
                        },
                        loading: false,
                    },
                    {
                        text: '取消',
                        theme: 'default',
                        handle: () => {
                            this.$emit('Close')
                        },
                    },
                ])
            },
            handleVisibleChange(scope, data) {
                if (data) {
                    const { factors, meterUtensilOptions } = scope.row
                    const $index = scope.$index
                    const meterIds = factors.map((item) => item.meterUtensilId)

                    if (meterIds && meterIds.length !== 0) {
                        const result = meterUtensilOptions.map((item) => {
                            item.disabled = meterIds.includes(item.value)
                            return item
                        })
                        this.$set(this.formData.tableData[$index], 'meterUtensilOptions', result)
                    }
                }
            },

            // 展开
            handleExpandChange(row, expandedRows) {
                const { factors, calculationRule = '', id } = row

                // const isExpand = expandedRows.find((row) => row.id === row.id)
                const findIndex = this.formData.tableData.findIndex((item) => item.id === id)
                // if (!isExpand) {
                //     const node = document.querySelector(`.key_${id}`)
                //     if (node) {
                //         const textContent = node.textContent || ''
                //         this.$set(
                //             this.formData.tableData[findIndex],
                //             'calculationRule',
                //             textContent
                //         )
                //     }

                //     return
                // }
                if (calculationRule.trim().length !== 0) {
                    return
                }

                let textContentArray = []
                factors.map((item) => {
                    if (item.meterUtensilId) {
                        const textContext = item.properties.map(
                            (subItem) => `#${subItem}_${item.meterUtensilId}$`
                        )
                        textContentArray = [...textContentArray, ...textContext]
                    }
                })
                if (textContentArray && textContentArray.length !== 0) {
                    this.$set(
                        this.formData.tableData[findIndex],
                        'calculationRule',
                        textContentArray.join(' ')
                    )
                }
            },
            // 删除单个
            handleRemoveTag(scope, value, index) {
                let { factors, calculationRule, id, meterUtensilOptions } = scope.row
                const node = document.querySelector(`.key_${id}`)
                if (!node) {
                    return
                }
                const $index = scope.$index
                const propertiesOptions = this.propertiesOptions

                const textContent = node.textContent || ''
                const currentSelect = factors[index]

                if (value && currentSelect) {
                    const { meterUtensilId } = currentSelect
                    const meterName = this.getMeterNameById(meterUtensilId, meterUtensilOptions)
                    const propertiesName = this.getPropertiesNameByCode(value, propertiesOptions)
                    calculationRule = textContent.replace(`#${propertiesName}_${meterName}$`, '')
                    const newCalculationRule = this.transformToken(
                        calculationRule,
                        scope,
                        'en'
                    ).join(' ')
                    this.$set(
                        this.formData.tableData[$index],
                        'calculationRule',
                        newCalculationRule
                    )
                }
            },

            // 添加
            handleChangeMeter(scope, index) {
                let { calculationRule = '', factors, id } = scope.row
                const $index = scope.$index
                const node = document.querySelector(`.key_${id}`)
                if (!node) {
                    return
                }
                const textContent = node.textContent || ''

                const currentSelect = factors[index]
                if (currentSelect) {
                    const { properties = [], meterUtensilId } = currentSelect

                    // ID字符
                    const flatMeter = properties.map((item) => `#${item}_${meterUtensilId}$`)

                    // zh->en
                    const newText = this.transformToken(textContent, scope, 'En').join(' ')

                    const newProperties = flatMeter.filter((item) => newText.indexOf(item) === -1)
                    newProperties.forEach((item) => (calculationRule += ` ${item} `))

                    this.$set(this.formData.tableData[$index], 'calculationRule', calculationRule)
                }
            },
            normalizeData() {
                const { tableData } = this.formData
                const result = []
                tableData.forEach((element) => {
                    const { id, name, property, factors = [] } = element
                    const node = document.querySelector(`.key_${id}`)

                    const calculationRule = node ? node.textContent : ''

                    const newCalculationRule = this.transformToken(
                        calculationRule,
                        { row: element },
                        'en'
                    )
                        .join('')
                        .replace(/\s/g, '')

                    result.push({
                        id: isNaN(id) ? '' : id,
                        name,
                        property,
                        calculationRule: newCalculationRule,
                        factors: factors
                            .map((factor) => ({
                                meterUtensilId: factor.meterUtensilId,
                                properties: factor.properties.join(','),
                            }))
                            .filter((item) => item.meterUtensilId),
                    })
                })
                return result
            },

            handleAddItem(scope) {
                const $index = scope.$index
                const { tableData } = this.formData
                this.formData.tableData = tableData.map((item, index) => {
                    if (index === $index) {
                        item.factors.push({ meterUtensilId: '', properties: [] })
                    }
                    return item
                })
            },
            handleRemoveItem(scope, _index) {
                let { factors, id, meterUtensilOptions } = scope.row
                const $index = scope.$index
                const currentSelect = factors[_index]

                const node = document.querySelector(`.key_${id}`)
                if (!node) {
                    return
                }
                const propertiesOptions = this.propertiesOptions
                const textContent = node.textContent || ''

                if (currentSelect) {
                    const { properties, meterUtensilId } = currentSelect
                    const codeArray = properties.map((value) => {
                        const meterName = this.getMeterNameById(meterUtensilId, meterUtensilOptions)
                        const propertiesName = this.getPropertiesNameByCode(
                            value,
                            propertiesOptions
                        )
                        return `#${propertiesName}_${meterName}$`
                    })

                    let resultText = textContent
                    codeArray.forEach((item) => (resultText = resultText.replace(item, ' ')))
                    const newText = this.transformToken(resultText, scope, 'En').join(' ')
                    this.$set(this.formData.tableData[$index], 'calculationRule', newText)
                }

                const { tableData } = this.formData
                this.formData.tableData = tableData.map((item, index) => {
                    if (index === $index) {
                        item.factors = item.factors.filter((_, index) => {
                            return index !== _index
                        })
                    }
                    return item
                })
            },
            submitForm() {
                const params = this.normalizeData()
                const { id } = this.formData
                // for (let i = 0; i < params.length; i++) {
                //     const item = params[i]
                //     const node = document.querySelector(`.key_${item.id}`)
                //     if (node) {
                //         item.calculationRule = node.textContent || ''
                //     }

                //     if (!item.calculationRule) {
                //         passthrough = true
                //         this.$message.warning('你有未填写的表达式，请修改')
                //         return
                //     }
                //     if (!item.factors || (item.factors && item.factors.length === 0)) {
                //         passthrough = true
                //         this.$message.warning('选择计量器具以及测点名称')
                //         return
                //     }

                //     for (let j = 0; j <script item.factors.length; j++) {
                //         const subItem = item.factors[j]
                //         if (!subItem.meterUtensilId) {
                //             passthrough = true
                //             this.$message.warning('请选择实体计量器具名称')
                //             return
                //         }
                //         if (!subItem.properties) {
                //             passthrough = true
                //             this.$message.warning('请选择实体测点名称')
                //             return
                //         }
                //     }
                // }
                updatePropertyCalExpression(id, params).then((result) => {
                    if (result.code == 200) {
                        this.$message.success(result.msg)
                        this.$emit('Close', true)
                    }
                })
            },
        },
    }
</script>
<template>
    <el-form
        label-position="top"
        ref="ruleForm"
        v-loading="loading"
        element-loading-background="rgba(0, 0, 0, 0.3)"
    >
        <div class="header-wrapper">
            <el-select
                v-model="formData.meterType"
                :clearable="false"
                filterable
                placeholder="请选择"
                transfer
                size="small"
                disabled
            >
                <el-option
                    v-for="item in meterTypeOptions"
                    :key="item.code"
                    :value="item.code"
                    :label="item.name"
                />
            </el-select>
        </div>
        <RlTable
            :is-pagination="false"
            :border="false"
            :data="formData.tableData"
            :initData="false"
            :search="false"
            ref="rlTable"
            :height="700"
            :defaultExpandAll="true"
            class="customRlTableClass"
            @expand-change="handleExpandChange"
        >
            <template #default>
                <el-table-column type="expand">
                    <template slot-scope="scope">
                        <el-form-item>
                            <div
                                class="expression-wrapper"
                                :class="`key_${scope.row.id}`"
                                contenteditable="true"
                                placeholder="请输入表达式"
                            >
                                <template
                                    v-for="item in transformToken(scope.row.calculationRule, scope)"
                                >
                                    <span
                                        contenteditable="false"
                                        class="code"
                                        v-if="isSnowflakeId(item)"
                                        >{{ item }}&nbsp;</span
                                    >
                                    <span contenteditable="true" v-else
                                        >&nbsp;{{ item }}&nbsp;</span
                                    >
                                </template>
                            </div>
                        </el-form-item>
                    </template>
                </el-table-column>
                <el-table-column label="虚拟测点名称" width="180">
                    <template slot-scope="scope">
                        <el-form-item> {{ scope.row.name || '--' }} </el-form-item>
                    </template>
                </el-table-column>
                <el-table-column label="实体计量器具名称, 实体测点名称">
                    <template slot="header">
                        <div class="customHeader">
                            <span class="item setWidth">实体计量器具名称</span>
                            <span class="item">实体测点名称</span>
                        </div>
                    </template>
                    <template slot-scope="scope">
                        <div
                            v-for="(item, index) in scope.row.factors"
                            class="factors-wrapper"
                            :key="index"
                        >
                            <el-select
                                v-model="item.meterUtensilId"
                                :clearable="false"
                                filterable
                                placeholder="请选择"
                                transfer
                                style="width: 25%"
                                size="small"
                                @visible-change="(data) => handleVisibleChange(scope, data)"
                            >
                                <el-option
                                    v-for="item in scope.row.meterUtensilOptions"
                                    :key="item.value"
                                    :value="item.value"
                                    :label="item.key"
                                    :disabled="item.disabled"
                                />
                            </el-select>

                            <el-select
                                v-model="item.properties"
                                :clearable="false"
                                filterable
                                placeholder="请选择测点(可多选)"
                                transfer
                                size="small"
                                multiple
                                style="width: 50%; margin-left: 10px"
                                @remove-tag="(data) => handleRemoveTag(scope, data, index)"
                                @change="(data) => handleChangeMeter(scope, index)"
                            >
                                <el-option
                                    v-for="item in propertiesOptions"
                                    :key="item.property"
                                    :value="item.property"
                                    :label="item.name"
                                />
                            </el-select>

                            <el-button
                                icon="el-icon-plus"
                                circle
                                size="small"
                                style="margin-left: 10px"
                                @click="handleAddItem(scope)"
                            ></el-button>
                            <el-button
                                icon="el-icon-close"
                                circle
                                size="small"
                                v-if="scope.row.factors && scope.row.factors.length > 1"
                                @click="handleRemoveItem(scope, index)"
                            ></el-button>
                        </div>
                    </template>
                </el-table-column>
            </template>
        </RlTable>
    </el-form>
</template>
<style lang="scss" scoped>
    ::v-deep .customRlTableClass {
        &.conataner-resize {
            position: static;
        }

        .rltable {
            padding: 0 !important;
        }

        .rltable-head {
            margin-bottom: 0 !important;
        }
        .el-form-item {
            margin-bottom: 0 !important;
        }
    }

    .header-wrapper {
        display: flex;
        margin-bottom: 8px;
    }

    .expression-wrapper {
        min-height: 100px;
        padding: 4px 12px;
        margin: 10px 20px;
        border: 1px solid #224781;
        background: #0e3165;

        .code {
            padding: 2px 4px;
            font-size: 11px;
            margin-right: 8px;
            border-radius: 6px;
            background: #4572a5;
            border: 1px solid #d9e5f345;
        }
    }
    .factors-wrapper {
        padding-bottom: 6px;
    }
    .customHeader {
        display: inline-flex;
        width: 100%;
        .item {
            flex: 1;
        }
        .setWidth {
            width: 10%;
        }
    }

    ::v-deep .el-table__expanded-cell {
        background: $table-defalut-tr-bg !important;

        &:hover {
            background: $table-defalut-tr-bg !important;
        }
    }
</style>
